/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.icee.myth.manager.web;

import com.icee.myth.manager.Manager;
import com.icee.myth.manager.db.DbHandler;
import com.icee.myth.utils.Consts;
import com.icee.myth.utils.LogConsts;
import com.icee.myth.utils.MLogger;
import com.icee.myth.utils.RandomGenerator;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import java.util.TreeMap;

/**
 * 注意HttpServerHandlerToWeb是在OrderedMemoryAwareThreadPoolExecutor
 * 线程池执行的。所以调用的WebServer的函数要加锁。
 *
 * @author yangyi
 */
public class WebServer {
    /**
     * PlayerInfo => sessionid
     */
    private HashMap<String, String> playersToSessMap;
    /**
     * sessionid => PlayerInfo
     */
    private TreeMap<String, PlayerInfo> sessToPlayerInfoMap;
    public int maxCid;

    public boolean init(DbHandler dbHandler) {
        playersToSessMap = new HashMap<String, String>();
        sessToPlayerInfoMap = new TreeMap<String, PlayerInfo>();
        return dbHandler.getMaxCid(this);
    }

    synchronized public PlayerInfo getPlayerInfoByPassport(String thirdPartyUserId) {
        String sessionId = playersToSessMap.get(thirdPartyUserId);
        if (sessionId != null) {
            PlayerInfo info = sessToPlayerInfoMap.get(sessionId);
            if (info != null) {
                if (info.time >= System.currentTimeMillis()) {
                    info.time = System.currentTimeMillis() + Manager.INSTANCE.sessionPeriod;
                    return info;
                }
            } else {
                MLogger.getlogger().debuglog(LogConsts.LOGLEVEL_ERROR, "playersToSessMap contanis but sessToPlayerInfoMap not contains sesionid " + sessionId);
            }
        }
        return null;
    }

    synchronized public PlayerInfo newPlayerInfo(DbHandler dbHandler, String passport) {
        PlayerInfo playerInfo = dbHandler.getPlayerInfoFromDB(passport);
        if (playerInfo == null) {
            if (dbHandler.insertPlayerInfo(passport, maxCid)) {
                playerInfo = new PlayerInfo(passport, maxCid, 0, 0);
                maxCid++;
            }
        }
        if (playerInfo != null) {
            long now = System.currentTimeMillis();
            playerInfo.time = now + Manager.INSTANCE.sessionPeriod;
            String sessionId = getSessionId();
            int retry = 0;
            while (retry++ < Consts.PRODUCEKEYMAXRETRYTIMES) {
                if (!sessToPlayerInfoMap.containsKey(sessionId)) {
                    playerInfo.sessionId = sessionId;
                    playersToSessMap.put(playerInfo.thirdPartyUserId, playerInfo.sessionId);
                    sessToPlayerInfoMap.put(playerInfo.sessionId, playerInfo);
                    if (sessToPlayerInfoMap.size() >= Manager.INSTANCE.maxSessionNum) {
                        for (Iterator<PlayerInfo> it = sessToPlayerInfoMap.values().iterator(); it.hasNext(); ) {
                            PlayerInfo pi = it.next();
                            if (pi.time <= now) {
                                playersToSessMap.remove(pi.thirdPartyUserId);
                                it.remove();
                            }
                        }
                    }
                    return playerInfo;
                }
                sessionId = getSessionId();
            }
        }
        return null;
    }

    synchronized public PlayerInfo GetPlayerInfoBySessinoId(String sessionId) {
        PlayerInfo info = sessToPlayerInfoMap.get(sessionId);
        if (info != null) {
            if (info.time >= System.currentTimeMillis()) {
                return info;
            } else {
                MLogger.getlogger().debuglog(LogConsts.LOGLEVEL_ERROR, "[" + new Date(System.currentTimeMillis()) + "] session [" + sessionId + "] out of time");
            }
        } else {
            MLogger.getlogger().debuglog(LogConsts.LOGLEVEL_ERROR, "[" + new Date(System.currentTimeMillis()) + "] session [" + sessionId + "] not found");
        }
        return null;
    }

    synchronized public void logout(String passport) {
        String sessionId = playersToSessMap.get(passport);
        if (sessionId != null) {
            sessToPlayerInfoMap.remove(sessionId);
        }
        playersToSessMap.remove(passport);
    }

    private String getSessionId() {
        String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder sb = new StringBuilder();
        Random random = RandomGenerator.INSTANCE.generator;
        for (int i = 0; i < 12; i++) {
            sb.append(base.charAt(random.nextInt(base.length())));
        }
        return sb.toString();
    }

}
